package test.ground.netty.netty.my;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;

import java.util.concurrent.TimeUnit;

/** 该类继承了ChannelInboundHandlerAdapter方法，目的是为了重写channelActive 和channelInactive 2个方法 *      channelActive   方法是： 在通道建立时，可以知道此时的客户端和服务端已经建立了连接 *      channelInactive 方法是： 在通道断开后，可以知道此时的客户端已经和服务断断开了连接，需要在这个方法中设置重连客户端方法 *
 *  * 该类实现了netty的接口TimerTask,目的是为了重写run()方法 *
 *  run(TimeOut timeout) 方法是：写具体的重连方案 * *
 *  该类实现了RireChannelHandlers 这个接口，目的是为了重写channelHandlers()方法 *
 *  channelHandlers() 方法是： 获得所有的通道配置处理的channelHandler,包括netty提供的和自定义的实现的，
 *  重点是该类并没有实现这个接口，因为关于客户端的一些启动项配置参数，我们在这里是并不知道客户端要怎样配置的，
 *  所以这才是把该类定义抽象类的关键 *
 *  让子类去实现这个方法更为合理。 *
 *  * @Sharabel 标签 * 　　　　该注解的目的是在每次重连时，可以让此类中的的channelhandler可以共享，多次使用 *
 */
@Sharable
public abstract class ClientReconnectHandler extends ChannelInboundHandlerAdapter implements TimerTask,FireChannelHandlers {

    private final ChannelContainer channel =new ChannelContainer();
    protected final HashedWheelTimer timer = new HashedWheelTimer();
    private int reconnectCount;
    private final Bootstrap bootstrap;
    private final String host;
    private final int port;

    public ClientReconnectHandler(Bootstrap bootstrap, String host, int port) {
        this.bootstrap = bootstrap;
        this.host = host;
        this.port = port;
    }

    //当通道建立时
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("当前链路已经激活了，重连尝试次数重新置为0");
        reconnectCount = 0;
        channel.onActive(ctx.channel());
        ctx.fireChannelActive();
    }
    //通道关闭时启动重连
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("通道关闭,将再次进行重连");
        channel.onInactive();
        if (reconnectCount < 12) {
            reconnectCount++;
            int timeout = 2 << reconnectCount;
            System.out.println("重连第"+reconnectCount+"次,timeout:"+timeout);
            timer.newTimeout(this, timeout, TimeUnit.MILLISECONDS);
        }
        ctx.fireChannelInactive();
    }

    @Override
    public void run(Timeout timeout) throws Exception {
        ChannelFuture channelFuture;
        synchronized (bootstrap) {
            bootstrap.handler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(channelHandlers());
                }
            });
            channelFuture = bootstrap.connect(host,port);
        }

        //添加重连监听
        channelFuture.addListener((ChannelFutureListener) channelFuture1 -> {
            boolean success = channelFuture1.isSuccess();
            if(!success){
                System.out.println("重连失败");
                channelFuture1.channel().pipeline().fireChannelInactive();
            }else{
                System.out.println("重连成功");
            }
        });
    }

    public ChannelContainer getChannel() {
        return channel;
    }


    public class ChannelContainer{
        private Channel channel;


        public boolean isActive(){
            return channel!=null && channel.isActive();
        }

        public void onActive(Channel channel){
            this.channel = channel;
        }

        public void onInactive(){
            this.channel = null;
        }

        public Channel getChannel() {
            return channel;
        }


    }
}